
//带有泛型并且增加缩容机制
public class ArrayList3<E> {


    private  int size;

    private E[] elements;

    private static final int DEFAULT_CAPACITY=10;

    private static final int ELEMENT_NOT_FOUND =-1;

    /**
     * 带参数的构造函数
     * @param capacity
     */
    public ArrayList3(int capacity){
//        下面写的不是太好
        /*if(capacity<=0){
            //抛出异常
            throw new RuntimeException("参数传递错误");
        }
        if(capacity<DEFAULT_CAPACITY){
            elements=new int[DEFAULT_CAPACITY];
        }else{
            elements=new int[capacity];
        }*/


//        可以变换成这样
        capacity=capacity<DEFAULT_CAPACITY?DEFAULT_CAPACITY:capacity;
        this.elements=(E[]) new Object[capacity];
    }

    /**
     * 无参构造函数
     */
    public ArrayList3(){
        this(DEFAULT_CAPACITY);
    }


    /**
     * 得到指定位置元素
     * @param index
     * @return
     */
    public E get(int index){
        judgeIndexOutOfBounds(index);
        return elements[index];
    }

    private void judgeIndexOutOfBounds(int index) {
        if(index <0 || index >=size){
            throw new IndexOutOfBoundsException("index="+ index +",size="+size);
        }
    }

    /**
     * 查找某个元素的位置
     * @param element
     * @return
     */
    public int indexOf(E element){
        if(element==null){
            for (int i = 0; i < size; i++) {
                if(elements[i]==null)return i;
            }
        }else{
            //element!=null
            for(int i=0;i<size;i++){
                if(element.equals(elements[i])) return i;
            }
        }
        return ELEMENT_NOT_FOUND;
    }


    /**
     * 得到数组长度
     *
     * @return
     */
    public int size() {
        return size;
    }

    /**
     * 判断数组是否包含元素
     *
     * @return
     */
    public boolean isEmpty() {
        return size==0;
    }

    /**
     * 添加元素
     * @param element
     */
    public void add(E element){
        add(size,element);
    }

    /**
     * 指定位置添加元素
     * @param index
     * @param element
     */
    public  void  add(int index,E element){
        if(index>size || index<0){
            throw new IndexOutOfBoundsException("数组角标越界");
        }

        //保证有size+1的容量
        ensureCapacity(size+1);
        for (int i = size-1; i >=index ; i--) {
            elements[i+1]=elements[i];
        }
        this.elements[index]=element;
        size++;
    }

    /**
     * 确保有足够的容量
     * @param capacity
     */
    private void ensureCapacity(int capacity) {
        int oldCapacity=elements.length;
        if(oldCapacity>=capacity)return;

        //新容量为旧容量的1.5倍
        int newCapacity=oldCapacity+(oldCapacity>>1);
        E[] arr=(E[]) new Object[newCapacity];
        for(int i=0;i<size;i++){
            arr[i]=elements[i];
        }
        this.elements=arr;
        System.out.println("老容量为+"+oldCapacity+"新容量为"+newCapacity);
    }

    /**
     * 指定位置更新元素
     * @param index
     * @param element
     * @return
     */
    public E set(int index,E element){
        judgeIndexOutOfBounds(index);
        E old=elements[index];
        elements[index]=element;
        return old;
    }

    /**
     * 删除指定元素
     * @param index
     */
    public void remove(int index){
        judgeIndexOutOfBounds(index);
        for (int i = index+1; i <size; i++) {
            elements[i-1]=elements[i];
        }
        elements[--size]=null;
        trim();
    }

    /**
     * 缩容机制
     */
    private void trim() {
        int oldCapacity=elements.length;
        int newCapacity=oldCapacity>>1;
        if(size >=newCapacity || oldCapacity<DEFAULT_CAPACITY)return;

        E[] arr=(E[]) new Object[newCapacity];
        for (int i = 0; i < size; i++) {
            arr[i]=elements[i];
        }
        this.elements=arr;
        System.out.println("老容量为+"+oldCapacity+"新容量为"+newCapacity);
    }

    /**
     * 查询是否包含某个元素
     * @param element
     * @return
     */
    public boolean contains(E element){
        return indexOf(element)!=ELEMENT_NOT_FOUND;
    }

    /**
     * 清空所有元素
     */
    public void clear(){
        for (int i = 0; i <size; i++) {
            elements[i]=null;
        }
        size=0;
    }

    public String toString(){
//        size=?,[1,2,3]
        StringBuilder sb=new StringBuilder();
        sb.append("size="+size+",[");
        for (int i = 0; i <size; i++) {
            sb.append(elements[i]);
            if(i!=size-1){
                sb.append(",");
            }
        }
        sb.append("]");
        return sb.toString();
    }

}
